#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<conio.h>
#include<windows.h>
#define GRID_WIDE 28     // 逻辑格子宽度（实际显示宽度=GRID_WIDE*2）
#define GRID_HIGH 26     // 逻辑格子高度
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define HIGHSCORE_FILE "highscore.dat"

int highscore = 0;        //最高分
int score = 0;            //得分
int add = 1;              //每个食物得分
int end = 0;              //游戏结束标志
int speed = 200;          //初始速度（毫秒）
int dirX = 1, dirY = 0;   //移动方向

// 设置控制台光标位置
void gotoxy(int x, int y) {
    COORD coord = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 设置控制台文本颜色
void setcolor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 隐藏光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cci = { sizeof(cci), FALSE };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}
int printsnake(void) {

    //清屏
    system("cls");

    gotoxy(35, 1);
    setcolor(6);
    printf("/^\\/^\\");      //蛇眼睛

    gotoxy(34, 2);
    printf("|__|  0|");        //蛇眼睛

    gotoxy(33, 2);
    setcolor(2);
    printf("_");

    gotoxy(25, 3);
    setcolor(12);
    printf("\\/");         //蛇信

    gotoxy(31, 3);
    setcolor(2);
    printf("/");

    gotoxy(37, 3);
    setcolor(6);
    printf("\\_/");           //蛇眼睛

    gotoxy(41, 3);
    setcolor(10);
    printf("\\");

    gotoxy(26, 4);
    setcolor(12);
    printf("\\____");             //舌头

    gotoxy(32, 4);
    printf("_________/");

    gotoxy(31, 4);
    setcolor(2);
    printf("|");

    gotoxy(43, 4);
    setcolor(10);
    printf("\\");

    gotoxy(32, 5);
    setcolor(2);
    printf("\\_______");       //蛇嘴

    gotoxy(44, 5);
    setcolor(10);
    printf("\\");

    //蛇身
    gotoxy(39, 6);
    printf("|     |                      \\");

    gotoxy(38, 7);
    printf("/      /                       \\");

    gotoxy(37, 8);
    printf("/      /                        \\ \\");

    gotoxy(35, 9);
    printf("/      /                           \\ \\");

    gotoxy(34, 10);
    printf("/      /                              \\ \\");

    gotoxy(33, 11);
    printf("/      /           _----_                \\ \\");

    gotoxy(32, 12);
    printf("/      /         _--     --_                |  |");

    gotoxy(31, 13);
    printf("(      (       _--    _--_    --_            _/  |");

    gotoxy(32, 14);
    printf("\\     --____--     _--    _--_    --_   --_--   /");

    gotoxy(33, 15);
    printf("--_           _--            --_           _--");

    gotoxy(35, 16);
    printf("---______--                      --___--");



    return 0;
}

// 从文件读取最高分
void LoadHighScore() {
    FILE* fp = fopen(HIGHSCORE_FILE, "r");
    if (fp != NULL) {
        fscanf(fp, "%d", &highscore);
        fclose(fp);
    }
    else {
        highscore = 0;  // 文件不存在时初始化
    }
}

// 保存最高分到文件
void SaveHighScore() {
    FILE* fp = fopen(HIGHSCORE_FILE, "w");
    if (fp != NULL) {
        fprintf(fp, "%d", highscore);
        fclose(fp);
    }
}

//欢迎界面
int welcometogame(void) {
    int choice;

    //绘制蛇的字符画
    printsnake();

    //输出标题
    //设置文本颜色
    setcolor(11);
    //设置光标位置
    gotoxy(45, 18);
    printf("贪吃蛇游戏");

    //绘制边框
    //选择边框颜色
    setcolor(14);

    for (size_t i = 20; i <= 26; i++) {           //控制行
        for (size_t j = 27; j <= 74; j++) {            //控制列
            //上下边框
            if (i == 20 || i == 26) {
                gotoxy(j, i);
                printf("-");
            }
            else if (j == 27 || j == 74) {     //左右边框
                gotoxy(j, i);
                printf("|");
            }
            else {
                gotoxy(j, i);
                printf(" ");
            }
        }
    }
    //输出菜单选项
    //设置文本颜色
    setcolor(12);
    //开始游戏
    gotoxy(35, 22);
    printf("1.开始游戏");

    //打印最高分
    gotoxy(55, 22);
    printf("2.游戏说明");

    //退出游戏
    gotoxy(35, 24);
    printf("3.退出游戏");

    //输出提示
    gotoxy(27, 27);
    printf("请选择【1 2 3】：");

    scanf("%d", &choice);

    //清除换行符
    getchar();

    return choice;
}

//游戏说明
int aboutgame(void) {
    int i = 0;
    int j = 0;

    //清屏
    system("cls");
    //输出标题
    setcolor(13);
    gotoxy(44, 3);
    printf("游戏说明");

    //绘制上下边框
    for (i = 6; i <= 22; i++) {      //控制行
        for (j = 20; j <= 75; j++) {
            //上下边框
            if (i == 6 || i == 22) {
                gotoxy(j, i);
                printf("=");
            }
            else if (j == 20 || j == 75) {
                gotoxy(j, i);
                printf("||");
            }
        }

    }
    //输出菜单
    setcolor(3);
    gotoxy(30, 8);
    printf("★ 1.不能撞到墙，不能咬到自己");

    setcolor(5);
    gotoxy(30, 11);
    printf("★ 2.F1加速前进，F2减速前进");

    setcolor(11);
    gotoxy(30, 14);
    printf("★ 4.使用wasd控制前进的方向");

    setcolor(13);
    gotoxy(30, 17);
    printf("★ 5.按下ESC键退出游戏");

    setcolor(12);
    gotoxy(20, 24);
    printf("按下回车键返回主界面");

    return 0;
}

// 蛇结构体
struct SNAKE {
    struct {
        int x, y;
    } body[GRID_WIDE * GRID_HIGH];
    int size;
} snake;

// 食物结构体
struct FOOD {
    int x, y;
} food;

// 初始化蛇
void initSnake() {
    snake.size = 3;
    snake.body[0].x = GRID_WIDE / 2;
    snake.body[0].y = GRID_HIGH / 2;
    for (int i = 1; i < snake.size; i++) {
        snake.body[i].x = snake.body[i - 1].x - 1;
        snake.body[i].y = snake.body[i - 1].y;
    }
}

// 生成新食物
void initFood() {
    int overlap;
    do {
        overlap = 0;
        food.x = rand() % (GRID_WIDE - 2) + 1; // 避开边界
        food.y = rand() % (GRID_HIGH - 2) + 1;
        for (int i = 0; i < snake.size; i++) {
            if (food.x == snake.body[i].x && food.y == snake.body[i].y) {
                overlap = 1;
                break;
            }
        }
    } while (overlap);
}

// 绘制游戏区域
void drawMap() {
    setcolor(6);
    for (int y = 0; y < GRID_HIGH; y++) {
        for (int x = 0; x < GRID_WIDE; x++) {
            gotoxy(x * 2, y);
            if (x == 0 || x == GRID_WIDE - 1 || y == 0 || y == GRID_HIGH - 1) {
                printf("■");
            }
            else {
                printf("  ");
            }
        }
    }
}

// 绘制游戏元素
void drawGame() {
    // 绘制蛇
    for (int i = 0; i < snake.size; i++) {
        gotoxy(snake.body[i].x * 2, snake.body[i].y);
        setcolor(10);
        printf(i == 0 ? "●" : "■");
    }

    // 绘制食物
    gotoxy(food.x * 2, food.y);
    setcolor(12);
    printf("★");
}

// 显示游戏信息
void showInfo(void) {
    setcolor(15);
    gotoxy(GRID_WIDE * 2 + 4, 2);
    printf("最高分: %d", highscore);
    gotoxy(GRID_WIDE * 2 + 4, 4);
    printf("当前得分: %d", score);
    gotoxy(GRID_WIDE * 2 + 4, 6);
    printf("移动速度: %dms", speed);

    //显示提示
    setcolor(12);
    gotoxy(72, 11);
    printf("温 馨 提 示 ");
    //绘制边框
    setcolor(10);
    gotoxy(60, 13);
    printf("=================================");
    gotoxy(60, 25);
    printf("=================================");
    //输出提示信息
    setcolor(13);
    gotoxy(64, 14);
    printf("※ 吃掉每个食物得分：%d分", add);
    gotoxy(64, 16);
    printf("※ 不能撞到墙壁，不能咬到自己");
    gotoxy(64, 18);
    printf("※ F1加速前进，F2减速前进");
    gotoxy(64, 20);
    printf("※ 使用上下左右控制前进的方向");
    gotoxy(64, 22);
    printf("※ 按下ESC退出游戏");
    return;
}

// 碰撞检测
int checkCollision() {
    // 撞墙检测
    if (snake.body[0].x <= 0 || snake.body[0].x >= GRID_WIDE - 1 ||
        snake.body[0].y <= 0 || snake.body[0].y >= GRID_HIGH - 1) {
        return 1;
    }

    // 自撞检测
    for (int i = 1; i < snake.size; i++) {
        if (snake.body[0].x == snake.body[i].x &&
            snake.body[0].y == snake.body[i].y) {
            return 1;
        }
    }
    return 0;
}

// 游戏主循环
void gameLoop() {
    system("cls");
    hideCursor();
    drawMap();
    initSnake();
    initFood();

    while (!end) {
        // 处理输入
        if (_kbhit()) {
            int key = _getch();
            switch (key) {
            case 'w': case 'W': if (dirY != 1) { dirX = 0; dirY = -1; } break;
            case 's': case 'S': if (dirY != -1) { dirX = 0; dirY = 1; } break;
            case 'a': case 'A': if (dirX != 1) { dirX = -1; dirY = 0; } break;
            case 'd': case 'D': if (dirX != -1) { dirX = 1; dirY = 0; } break;
            case 27: end = 1; break; // ESC
            }
        }

        // 功能键检测
        if (GetAsyncKeyState(VK_F1) & 0x8000) {
            speed = min(500, speed + 20);   // 加速
        }
        if (GetAsyncKeyState(VK_F2) & 0x8000) {
            speed = max(50, speed - 20); // 减速
        }

        // 移动蛇身
        int lastX = snake.body[snake.size - 1].x;
        int lastY = snake.body[snake.size - 1].y;
        for (int i = snake.size - 1; i > 0; i--) {
            snake.body[i] = snake.body[i - 1];
        }

        // 移动蛇头
        snake.body[0].x += dirX;
        snake.body[0].y += dirY;

        // 吃食物检测
        if (snake.body[0].x == food.x && snake.body[0].y == food.y) {
            snake.size++;
            score += add;
            speed += 10;
            if (score > highscore) {
                highscore = score;
            }
            initFood();
        }

        // 清除旧蛇尾
        gotoxy(lastX * 2, lastY);
        printf("  ");

        // 绘制游戏元素
        drawGame();
        showInfo();

        // 碰撞检测
        if (checkCollision()) {
            end = 1;
            gotoxy(GRID_WIDE * 2 + 4, 10);
            setcolor(12);
            printf("游戏结束！按任意键继续...");
            _getch();
        }

        Sleep(500 - speed);
    }
    showInfo();
    SaveHighScore();  // 游戏结束后保存
}

int main() {

    int choice;
    srand(time(NULL));
    system("mode con cols=80 lines=30");

    LoadHighScore();  // 启动时加载最高分

    while (1) {
        system("cls");
        setcolor(11);
        //欢迎界面
        choice = welcometogame();

        switch (choice) {
        case 1:
            end = 0;
            score = 0;
            gameLoop();
            break;
        case 2:
            aboutgame();
            system("pause");
            break;
        case 3:
            return 0;
        }
    }
}